﻿using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

public class TKChessBoardComponentModel : BaseComponentModel
{
    private System.Random random = new System.Random(DateTime.Now.Millisecond);
    private Thread asyncThread;
    private Queue<Action> callbackQueue = new Queue<Action>();
    private TK_ChessBoard chessBoard;
    public DataModel<Vector3> posDM;
    public DataModel<bool> showCircle;
    public DataModel<Vector3> smallCirclePos;
    public DataModel<Vector3> largeCirclePos;
    public ListComponentModel<TKChessComponentModel> chessLCM;
    private TKChessComponentModel selectedChessCM;
    private int selfCamp = 0;
    private TKSelectCampPanelModel panelCM;
    public TKChessBoardComponentModel(int camp, TKSelectCampPanelModel panelCM)
    {
        this.panelCM = panelCM;
        selfCamp = camp;
        posDM = new DataModel<Vector3>(new Vector3(0, 0, -1));
        showCircle = new DataModel<bool>(false);
        smallCirclePos = new DataModel<Vector3>(new Vector3(0, 0, 1));
        largeCirclePos = new DataModel<Vector3>(new Vector3(0, 0, 1));
        chessLCM = new ListComponentModel<TKChessComponentModel>();
        chessBoard = new TK_ChessBoard();
        BaseChess[] chessArray = chessBoard.GetAllChessArray();
        for (int i = 0; i < chessArray.Length; i++)
        {
            chessLCM.AddNotUpdate(new TKChessComponentModel(chessArray[i]));
        }
        chessLCM.Update();
        UpdateChessPos();
        if (selfCamp != 0)
        {
            ComputerTryMove();
            panelCM.isCalculatingDM.Set(true);
        }
    }
    public void ExecuteUpdate()
    {
        lock (callbackQueue)
        {
            while (callbackQueue.Count != 0)
            {
                Action action = callbackQueue.Dequeue();
                if (action != null)
                {
                    try
                    {
                        action();
                    }
                    catch (Exception e)
                    {
                        Debug.LogError(e.Message);
                    }
                }
            }
        }
    }
    private Pos ConvertV2ToPos(Vector2 v2Pos)
    {
        Vector2 v2 = v2Pos * 2 + new Vector2(9f, 9f);
        Pos pos = new Pos(Convert.ToInt32(v2.x), Convert.ToInt32(v2.y));
        return pos;
    }
    public void UpdateChessPos()
    {
        Dictionary<BaseChess, Pos> dict = new Dictionary<BaseChess, Pos>();
        int offLineCounter = 0;
        for (int i = 0; i < chessBoard.GetCampCount(); i++)
        {
            BaseChess[] offlineList = chessBoard.GetAllOfflineChessByCamp(i);
            for (int j = 0; j < offlineList.Length; j++)
            {
                Pos pos = new Pos((offLineCounter / 19) + chessBoard.GetWidth() + 1, offLineCounter % 19);
                offLineCounter++;
                dict.Add(offlineList[j], pos);
            }
            BaseChess[] onlineList = chessBoard.GetAllOnlineChessByCamp(i);
            for (int j = 0; j < onlineList.Length; j++)
            {
                Pos pos = chessBoard.GetGridByChess(onlineList[j]).GetPos();
                dict.Add(onlineList[j], pos);
            }
        }
        for (int i = 0; i < chessLCM.GetCount(); i++)
        {
            TKChessComponentModel ccm = chessLCM.GetByIndex(i);
            Pos pos = dict[ccm.chess];
            float vx, vy;
            vx = pos.x / 2f - 4.5f;
            vy = pos.y / 2f - 4.5f;
            Vector3 v3 = new Vector3(vx, vy, -2);
            ccm.UpdatePos(v3);
        }

        bool isNotSelfRound = (chessBoard.GetCurrentRoundIndex() != selfCamp);
        panelCM.isCalculatingDM.Set(isNotSelfRound && !chessBoard.IsEnd());
        showCircle.Set(chessBoard.record.Count > 0);
        if (showCircle.Get())
        {
            (Pos, Pos) lastPath = chessBoard.record[chessBoard.record.Count - 1].Item1;
            Vector3 startWorldPos, endWorldPos;
            startWorldPos = new Vector3(lastPath.Item1.x / 2f - 4.5f, lastPath.Item1.y / 2f - 4.5f, -3);
            endWorldPos = new Vector3(lastPath.Item2.x / 2f - 4.5f, lastPath.Item2.y / 2f - 4.5f, -3);
            smallCirclePos.Set(startWorldPos);
            largeCirclePos.Set(endWorldPos);
        }

        if (chessBoard.IsEnd())
        {
            panelCM.showFunction.Set(false);
        }
    }
    public void ClickOnBoard(Vector2 clickPosition)
    {
        if (chessBoard.IsEnd())
        {
            Debug.LogWarning("游戏已结束");
            return;
        }
        if (!(chessBoard.GetCurrentRoundIndex() == selfCamp))
        {
            Debug.LogWarning("电脑正在思考");
            return;
        }
        if (selectedChessCM == null)
        {
            return;
        }
        else
        {
            selectedChessCM.ChangeSelectedStatus(false);
            Pos clickPos = ConvertV2ToPos(clickPosition);
            if (clickPos.x >= 0 && clickPos.x < chessBoard.GetWidth() && clickPos.y >= 0 && clickPos.y < chessBoard.GetHeight())
            {
                Pos startPos = chessBoard.GetGridByChess(selectedChessCM.chess).GetPos();
                TryMove((startPos, clickPos));
            }
            selectedChessCM = null;
        }

    }
    public void ClickOnChess(TKChessComponentModel chessCM)
    {
        if (chessBoard.IsEnd())
        {
            Debug.LogWarning("游戏已结束");
            return;
        }
        if (!(chessBoard.GetCurrentRoundIndex() == selfCamp))
        {
            Debug.LogWarning("电脑正在思考");
            return;
        }
        if (!chessBoard.CheckChessIsOnline(chessCM.chess))
        {
            selectedChessCM.ChangeSelectedStatus(false);
            selectedChessCM = null;
            return;
        }
        else
        {
            if (selectedChessCM != null)
            {
                if (chessCM.chess.GetCamp() != selfCamp)
                {
                    selectedChessCM.ChangeSelectedStatus(false);
                    TryMove((chessBoard.GetGridByChess(selectedChessCM.chess).GetPos(), chessBoard.GetGridByChess(chessCM.chess).GetPos()));
                    selectedChessCM = null;
                }
                else
                {
                    if (selectedChessCM == chessCM)
                    {
                        selectedChessCM.ChangeSelectedStatus(false);
                        selectedChessCM = null;
                    }
                    else
                    {
                        selectedChessCM.ChangeSelectedStatus(false);
                        selectedChessCM = chessCM;
                        selectedChessCM.ChangeSelectedStatus(true);
                    }
                }
            }
            else
            {
                if (chessCM.chess.GetCamp() != selfCamp)
                {
                    return;
                }
                else
                {
                    selectedChessCM = chessCM;
                    selectedChessCM.ChangeSelectedStatus(true);
                }
            }
        }

    }
    public void ComputerTryMove()
    {
        if (chessBoard.IsEnd())
        {
            Debug.LogWarning("游戏已结束");
            return;
        }
        lock (this)
        {
            if (asyncThread != null)
            {
                Debug.LogError("异步线程未执行完");
                return;
            }
            TK_ChessBoard cloneChessBoard = (TK_ChessBoard)chessBoard.CloneBoard();
            asyncThread = new Thread(new ParameterizedThreadStart((object cloneCB) =>
            {
                try
                {
                    //不让电脑下太快
                    int maxStepCount = 400000;
                    int minStepCount = 500000;
                    List<(Pos, Pos)> pathList = ((TK_ChessBoard)cloneCB).LimitGetBestPath(cloneChessBoard.GetCurrentRoundIndex(), minStepCount, maxStepCount);
                    if (pathList.Count == 0)
                    {
                        Debug.LogError("不可行动");
                        lock (callbackQueue)
                        {
                            callbackQueue.Enqueue(() =>
                            {
                                TryNotMove();
                            });
                        }
                    }
                    else
                    {
                        (Pos, Pos) confirmPath = pathList[random.Next(0, pathList.Count)];
                        lock (callbackQueue)
                        {
                            callbackQueue.Enqueue(() =>
                            {
                                TryMove(confirmPath);
                            });
                        }
                    }
                }
                catch (Exception e)
                {
                    Debug.LogError(e.Message);
                }
                lock (this)
                {
                    asyncThread = null;
                }
            }));
            asyncThread.Start(cloneChessBoard);
        }
    }
    private void TryMove((Pos, Pos) confirmPath)
    {
        bool result = chessBoard.TryMove(confirmPath);
        if (result)
        {
            UpdateChessPos();
            bool isNotSelfRound = (chessBoard.GetCurrentRoundIndex() != selfCamp);
            if (isNotSelfRound)
            {
                ComputerTryMove();
            }
        }
    }
    private void TryNotMove()
    {
        chessBoard.TryNotMove();
        bool isNotSelfRound = (chessBoard.GetCurrentRoundIndex() != selfCamp);
        panelCM.isCalculatingDM.Set(isNotSelfRound && !chessBoard.IsEnd());
        if (isNotSelfRound)
        {
            ComputerTryMove();
        }
    }
    public void Retract()
    {
        if (selectedChessCM != null)
        {
            selectedChessCM.ChangeSelectedStatus(false);
            selectedChessCM = null;
        }
        bool result = chessBoard.Retract(selfCamp);
        if (result)
        {
            CancelComputerTryMove();
            UpdateChessPos();
        }
    }
    public void CancelComputerTryMove()
    {
        lock (this)
        {
            if (asyncThread != null)
            {
                try
                {
                    asyncThread.Abort();
                }
                catch
                {
                    Debug.LogWarning("悔棋");
                }
                asyncThread = null;
            }
        }
    }
}
